#include "TThreadPool.h"
using namespace std;
TThreadPool::TThreadPool():running_(false)
{

}

TThreadPool::~TThreadPool()
{
    if (running_) Stop();
}

void TThreadPool::runInThread()
{
    while (running_)
    {
        TTask task(Take());
        if (task) task();
    }
}

void TThreadPool::Start(int numThreads)
{
    running_ = true;
    for (int i = 0; i < numThreads; i++)
    {
        threads_.push_back(thread(bind(&TThreadPool::runInThread, this)));
    }
}

void TThreadPool::Stop()
{
    {
        lock_guard<mutex> lock(mutex_);
        running_ = false;
        notempty_.notify_all();
    }
    for_each(threads_.begin(), threads_.end(), bind(&thread::join, placeholders::_1));
}

void TThreadPool::Run(const TTask& tk)
{
    lock_guard<mutex> lock(mutex_);
    queue_.push_back(move(tk));
    notempty_.notify_one();
}

void TThreadPool::Run(TTask&& tk)
{
    lock_guard<mutex> lock(mutex_);
    queue_.push_back(move(tk));
    notempty_.notify_one();
}

TTask TThreadPool::Take()
{
    unique_lock<mutex> lock(mutex_);
    while (queue_.empty() && running_)
    {
        notempty_.wait(lock);
    }
    TTask task;
    if (!queue_.empty())
    {
        task = queue_.front();
        queue_.pop_front();
    }
    return task;

}